package org.arain.baseii.aspect.point;

import java.lang.reflect.Method;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

import org.arain.baseii.aspect.annotation.SystemExceptionLog;
import org.arain.baseii.aspect.annotation.SystemServiceLog;
import org.arain.baseii.system.log.SystemLogDto;
import org.arain.baseii.system.log.SystemLogService;
import org.arain.baseii.system.oplog.SysOplogDto;
import org.arain.baseii.system.oplog.SysOplogService;
import org.arain.baseii.utils.AddressUtil;
import org.arain.baseii.utils.AppUtils;
import org.arain.baseii.utils.IDUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import net.sf.json.JSONObject;
/**
 * 
* <p>Title:SystemLogAspect </p>
* @author Arain
* @date2017年9月5日
 */
@Aspect  
@Component 
public class SystemLogAspect implements Ordered{  
	//注入Service用于把日志保存数据库  
	@Autowired  
	private SysOplogService logService;  
	@Autowired
	private SystemLogService systemLogService;
	//本地异常日志记录对象  
	private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);  

	//Controller层切点  
	@Pointcut("@annotation(org.arain.baseii.aspect.annotation.SystemServiceLog)")  
	public  void serviceAspect() {  
	}  
	
	 //Service层切点
	@Pointcut("@annotation(org.arain.baseii.aspect.annotation.SystemExceptionLog)")  
	public  void exceptionAspect() {  
	}
	
	@Pointcut("@annotation(org.arain.baseii.aspect.annotation.SystemLoginLog)")  
	public  void loginAspect() {  
	}

	/** 
	 * 前置通知 用于拦截Controller层记录用户的操作 
	 * 
	 * @param joinPoint 切点 
	 */  
	@AfterReturning("serviceAspect()")  
	public  void after(JoinPoint joinPoint) {  

		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
		//读取session中的用户  
		String userid = AppUtils.getRealName();
		//请求的IP  
		String ip = AddressUtil.getIpAddr(request); 
		String uri = request.getRequestURI();
		JSONObject object = new JSONObject();
		Enumeration<?> ee = request.getParameterNames();
		while (ee.hasMoreElements()) {
			String name = ee.nextElement().toString();
			object.accumulate(name, request.getParameter(name));
		}
		try {  
			//*========控制台输出=========*//  
			System.out.println("=====前置通知开始=====");  
			System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
			System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));  
			System.out.println("请求人:" + userid);  
			System.out.println("请求IP:" + ip);  
			//*========数据库日志=========*//  
			SysOplogDto sysOplogDto = new SysOplogDto();
			sysOplogDto.setLogDesc(getControllerMethodDescription(joinPoint));
			sysOplogDto.setLogIp(ip);
			sysOplogDto.setLogUrl(uri);
			sysOplogDto.setLogMethed((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
			sysOplogDto.setLogUser(userid);
			sysOplogDto.setLogData(object.toString());
			sysOplogDto.setOrgid(AppUtils.getOrgId().toString());
			sysOplogDto.setLogException("无");
			sysOplogDto.setLogSuccess("1");
			logService.save_01(sysOplogDto);
			System.out.println("=====前置通知结束=====");  
		}  catch (Exception e) {  
			//记录本地异常日志  
			logger.error("==前置通知异常==");  
			logger.error("异常信息:{}", e.getMessage());  
		}  
	}  
	
	
	@AfterThrowing(pointcut="exceptionAspect()",throwing="e")
    public void doAfterThrowing(JoinPoint joinPoint,Throwable e){
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		JSONObject object = new JSONObject();
		Enumeration<?> ee = request.getParameterNames();
		while (ee.hasMoreElements()) {
			String name = ee.nextElement().toString();
			object.accumulate(name, request.getParameter(name));
		}
		String userid = AppUtils.getRealName();
		//请求的IP  
		String ip = AddressUtil.getIpAddr(request);
		String uri = request.getRequestURI();
		try {  
			//*========控制台输出=========*//  
			System.out.println("=====异常通知开始=====");    
            System.out.println("异常代码:" + e.getClass().getName());    
            System.out.println("异常信息:" + e.getMessage());    
			System.out.println("异常方法方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
			System.out.println("方法描述:");  
			System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
			System.out.println("请求人:" + userid);  
			System.out.println("请求IP:" + ip);  
			//*========数据库日志=========*//
			SysOplogDto sysOplogDto = new SysOplogDto();
			sysOplogDto.setLogDesc(getControllerMethodDescription(joinPoint));
			sysOplogDto.setLogIp(ip);
			sysOplogDto.setLogUrl(uri);
			sysOplogDto.setLogMethed((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
			sysOplogDto.setLogUser(userid);
			sysOplogDto.setLogData(object.toString());
			sysOplogDto.setOrgid(AppUtils.getOrgId().toString());
			sysOplogDto.setLogException(e.getMessage());
			sysOplogDto.setLogSuccess("0");
			logService.save_01(sysOplogDto);
			System.out.println("=====异常通知结束=====");  
		}  catch (Exception ex) {
			logger.error("==前置通知异常==");  
			logger.error("异常信息:{}", ex.getMessage());
		}
    }

	/** 
	 * 获取注解中对方法的描述信息 用于Controller层注解 
	 * 
	 * @param joinPoint 切点 
	 * @return 方法描述 
	 * @throws Exception 
	 */  
	@SuppressWarnings("rawtypes")
	public  static String getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {  
		String targetName = joinPoint.getTarget().getClass().getName();  
		String methodName = joinPoint.getSignature().getName();  
		Object[] arguments = joinPoint.getArgs();  
		Class targetClass = Class.forName(targetName);  
		Method[] methods = targetClass.getMethods();  
		String description = "";  
		for (Method method : methods) {  
			if (method.getName().equals(methodName)) {  
				Class[] clazzs = method.getParameterTypes();  
				if (clazzs.length == arguments.length) {  
					description = method.getAnnotation(SystemServiceLog.class).description();  
					break;  
				}  
			}  
		}  
		return description;  
	}
	
	/**  
     * 获取注解中对方法的描述信息 用于service层注解  
     *  
     * @param joinPoint 切点  
     * @return 方法描述  
     * @throws Exception  
     */    
     public  static String getServiceMthodDescription(JoinPoint joinPoint)    
             throws Exception {    
        String targetName = joinPoint.getTarget().getClass().getName();    
        String methodName = joinPoint.getSignature().getName();    
        Object[] arguments = joinPoint.getArgs();    
        Class targetClass = Class.forName(targetName);    
        Method[] methods = targetClass.getMethods();    
        String description = "";    
         for (Method method : methods) {    
             if (method.getName().equals(methodName)) {    
                Class[] clazzs = method.getParameterTypes();    
                 if (clazzs.length == arguments.length) {    
                    description = method.getAnnotation(SystemExceptionLog.class).description();    
                     break;    
                }    
            }    
        }    
         return description;    
    }   
     @AfterReturning("loginAspect()")
     public  void login() {
    	 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    	 SystemLogDto dto = new SystemLogDto();
    	 dto.setId(IDUtil.genId());
    	 dto.setIp(AddressUtil.getIpAddr(request));
    	 dto.setOrgid(AppUtils.getOrgId()+"");
    	 dto.setUsername(AppUtils.getUserName());
    	 dto.setUserId(AppUtils.getUserId()+"");
    	 UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));  
    	 Browser browser = userAgent.getBrowser();  
    	 OperatingSystem os = userAgent.getOperatingSystem();
    	 dto.setMac(os.getName()+","+browser.getName());
    	 systemLogService.save_01(dto);
     }
	@Override
	public int getOrder() {
		return 1;
	}  
}
